package dao

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/google/uuid"
	"log"
	"order_srv/basic/config"
	inits "order_srv/basic/init"
	__ "order_srv/basic/orderproto"
	"order_srv/handler/models"
	"order_srv/pkg"
	"order_srv/untils"
	"strconv"
	"time"
)

// 取消订单
func CancelOrders(in *__.CanCelOrderReq) (int64, error) {
	var o models.Orders
	err := o.GetOrderInfo(int(in.OrderId))
	if err != nil {
		return 0, errors.New("查询订单失败" + err.Error())
	}
	if o.Id == 0 {
		return 0, errors.New("订单不存在")
	}

	if o.OrderStatus != 1 && o.OrderStatus != 2 {
		return 0, errors.New("该订单不是待接单、待上车状态，不能取消")
	}

	//if o.ServiceStartTime.Add(time.Minute*5).Unix() < time.Now().Unix() {
	//	return 0, errors.New("订单已超时5分钟，不能取消")
	//}

	if !pkg.Baid(in.Reason) {
		return 0, errors.New("取消原因包含敏感词")
	}

	c := models.OrderCancellation{
		OrderId:         uint64(in.OrderId),          // 订单id
		Reason:          in.Reason,                   // 取消原因
		Liability:       uint8(in.Liability),         // 承担责任
		CancellationFee: float64(in.CancellationFee), // 取消金额
		UserId:          uint64(in.UserId),           //操作人id
		Identity:        uint8(in.Identity),          // 操作人类型
	}
	if err := c.CreateCancel(); err != nil {
		return 0, errors.New("生成原因失败" + err.Error())
	}
	return int64(c.Id), nil
}

// 取消订单的列表
func CancelOrdersList(in *__.IsCanCelOrderReq) ([]*__.IsCanCelOrderList, error) {
	var o models.Orders
	o.UserId = uint32(in.UserId)
	list, err := o.GetCancelList()
	if err != nil {
		return nil, errors.New("查询失败" + err.Error())
	}
	var cancelList []*__.IsCanCelOrderList
	for _, v := range list {
		l := __.IsCanCelOrderList{
			OrderId:         int64(v.OrderId),
			OrderSn:         v.OrderSn,
			Mobile:          v.Mobile,
			DriverId:        int64(v.DriverId),
			Reason:          v.Reason,
			Liability:       int64(v.Liability),
			CancellationFee: float32(v.CancellationFee),
			Identity:        int64(v.Identity),
			DriverMobile:    v.DriverMobile,
			DriverRealName:  v.DriverRealName,
		}
		cancelList = append(cancelList, &l)
	}
	return cancelList, err
}

// 查询订单起终点纬度
func GetOrderLocation(orderId uint32) (models.OrderLatLnt, error) {
	var o models.OrderLatLnt
	o.OrderId = int32(orderId)
	if err := o.GetByOrderId(); err != nil {
		return models.OrderLatLnt{}, errors.New("查询失败" + err.Error())
	}
	return o, nil
}

// 订单行动轨迹
func OrderTrajectory(in *__.TrajectoryListReq) ([]*__.TrajectoryList, error) {
	var t models.Trajectory
	t.OrderId = uint32(in.OrderId)
	list, err := t.GetListByOrderId()
	if err != nil {
		return nil, errors.New("查询失败" + err.Error())
	}
	var trajectoryList []*__.TrajectoryList
	for _, v := range list {
		l := __.TrajectoryList{
			OrderId:   v.OrderId,
			Latitude:  float32(v.Latitude),
			Longitude: float32(v.Longitude),
			Point:     int64(v.Point),
		}
		trajectoryList = append(trajectoryList, &l)
	}
	return trajectoryList, err
}

// 记录轨迹经纬度
func RecordLocation(orderId uint32, lat, lnt float32, point int64) (int64, error) {
	var t models.Trajectory
	t.OrderId = orderId
	t.Latitude = float64(lat)
	t.Longitude = float64(lnt)
	t.Point = int8(point)
	if err := t.Create(config.DB); err != nil {
		return 0, errors.New("添加失败" + err.Error())
	}
	return int64(t.Id), nil
}

// 接收并记录轨迹经纬度
func ReceiveLocationInfo(in *__.RecordLocationReq) error {
	queueName := fmt.Sprintf("order_trajectory:%v", in.OrderId)
	msg, err := inits.NewRabbitMQSimple(queueName).ConsumeSimple()
	if err != nil {
		return errors.New("接收数据失败" + err.Error())
	}
	forever := make(chan bool)
	//启用协程处理消息
	go func() {
		for d := range msg {
			//消息逻辑处理，可以自行设计逻辑
			log.Printf("Received a message: %s", d.Body)
			var data models.Trajectory
			_ = json.Unmarshal(d.Body, &data)
			_, err = RecordLocation(data.OrderId, float32(data.Latitude), float32(data.Longitude), int64(data.Point))
			if err != nil {
				log.Printf("orderId:%v,lat:%v,lint:%v", data.OrderId, data.Latitude, data.Longitude)
				log.Printf("记录轨迹失败" + err.Error())
			}
			// 核心判断：当Point为5时，触发退出流程
			if data.Point == 5 {
				log.Println("订单完成，处理完成后退出")
				close(forever) // 关闭通道通知主程序退出
				return
			}
		}
	}()
	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	<-forever
	return nil
}

/*
创建订单
地址获取起点终点经纬度
获取起点终点距离
事务创建订单
记录起点终点经纬度
*/
// OrderCreate 创建订单
func OrderCreate(in *__.OrderCreateReq) (int64, error) {
	// 地址获取起点终点经纬度
	start, err := untils.GetCoordinates(in.StartLoc)
	if err != nil {
		return 0, errors.New("获取起点经纬度失败" + err.Error())
	}
	end, err := untils.GetCoordinates(in.EndLoc)
	if err != nil {
		return 0, errors.New("获取终点经纬度失败" + err.Error())
	}
	// 检查起点是否在服务围栏内
	startInFence, err := CheckLocationInServiceFence(start.Result.Location.Lat, start.Result.Location.Lng)
	if err != nil {
		return 0, errors.New("围栏检查失败: " + err.Error())
	}

	if !startInFence {
		return 0, errors.New("起点不在服务范围内")
	}
	// 检查终点是否在服务围栏内（可选）
	endInFence, err := CheckLocationInServiceFence(end.Result.Location.Lat, end.Result.Location.Lng)
	if err != nil {
		return 0, errors.New("围栏检查失败: " + err.Error())
	}

	if !endInFence {
		return 0, errors.New("终点不在服务范围内")
	}
	// 获取起点终点距离
	distance := untils.CalculateDistance(start.Result.Location.Lng, start.Result.Location.Lat, end.Result.Location.Lng, end.Result.Location.Lat)
	// 获取当前时间转化为订单编号
	timeStr := time.Now().Format(time.DateTime)
	parsedTime, err := time.Parse(time.DateTime, timeStr)
	if err != nil {
		log.Fatalf("解析时间失败: %v", err)
	}
	targetLayout := "20060102150405"
	// 格式化为目标字符串
	formattedStr := parsedTime.Format(targetLayout)

	// 处理时间安排 - 支持即时出行和未来预约
	var serviceTime time.Time

	// 判断是否为即时出行请求
	if in.ServiceStartTime == "" || in.ServiceStartTime == "immediate" {
		// 即时出行，设置服务时间为当前时间
		//serviceTime = time.Now()
		// 确保订单类型为实时单
		if in.OrderType != 1 {
			in.OrderType = 1 // 强制设置为实时单
		}
	} else {
		// 未来预约，解析预约时间
		serviceTime, err = time.Parse(time.DateTime, in.ServiceStartTime)
		if err != nil {
			return 0, errors.New("预约时间格式失败" + err.Error())
		}
		// 确保订单类型为预约单
		if in.OrderType != 2 {
			in.OrderType = 2 // 强制设置为预约单
		}
	}

	var city models.City
	city.Id = uint32(in.CityId)
	err = city.GetCity()
	if err != nil {
		return 0, errors.New("获取城市失败" + err.Error())
	}
	if city.Id == 0 {
		return 0, errors.New("城市信息不存在")
	}
	if in.CityId > 5 {
		return 0, errors.New("城市id错误")
	}

	if in.CarTypeId > 4 {
		return 0, errors.New("车辆类型错误")
	}

	if in.OrderType > 4 {
		return 0, errors.New("订单类型错误")
	}

	var o models.Orders
	o.OrderSn = uuid.NewString() + formattedStr //订单编号 雪花算法+时间戳 唯一性 可查性
	o.UserId = uint32(in.UserId)                //用户ID
	o.CityId = uint32(in.CityId)                //城市ID
	o.Distance = distance                       // 订单距离
	o.CarTypeId = int8(in.CarTypeId)            //车辆类型
	o.StartLoc = in.StartLoc                    // 订单起点
	o.EndLoc = in.EndLoc                        // 订单终点
	o.OrderType = int8(in.OrderType)            // 订单类型
	o.ServiceStartTime = serviceTime            // 订单服务开始时间
	o.Source = in.Source                        // 订单来源

	//判断车型是否存在
	if !(in.CarTypeId > 0 && in.CarTypeId < 5) {
		return 0, errors.New("没有此车型")
	}
	// 检查用户支付状态
	tempOrder := models.Orders{UserId: uint32(in.UserId)}
	if err = tempOrder.GetOrderUserPayStatus(); err != nil {
		return 0, errors.New("获取订单用户支付状态失败" + err.Error())
	}
	if tempOrder.OrderStatus == 4 {
		return 0, errors.New("当前用户未支付订单,无法创建订单")
	}

	// 创建订单
	if err := pkg.PublishMQ(&o); err != nil {
		//AMQP协议实现可靠性高 生产者→交换器→队列→消费者传递订单信息 实时性高 消息处理延迟低
		return 0, fmt.Errorf("发布订单失败")
	}

	// 开启事务
	tx := config.DB.Begin()

	// 首先创建订单以获取订单ID
	if err = o.Create(tx); err != nil {
		tx.Rollback()
		return 0, errors.New("创建订单失败" + err.Error())
	}

	// 记录起点终点经纬度
	var ol models.OrderLatLnt
	ol.OrderId = int32(o.Id)
	ol.StartLat = start.Result.Location.Lat
	ol.StartLint = start.Result.Location.Lng
	ol.EndLat = end.Result.Location.Lat
	ol.EndLnt = end.Result.Location.Lng
	if err = ol.Create(tx); err != nil {
		tx.Rollback()
		return 0, errors.New("记录起点终点经纬度失败" + err.Error())
	}

	// 提交事务
	if err = tx.Commit().Error; err != nil {
		tx.Rollback()
		return 0, errors.New("提交事务失败" + err.Error())
	}

	return int64(o.Id), nil
}

// CheckLocationInServiceFence 检查位置是否在服务围栏内
func CheckLocationInServiceFence(lat, lng float64) (bool, error) {
	// 从数据库获取所有有效的服务围栏
	var fences []models.Fence
	if err := config.DB.Where("status = ? AND type = ?", 1).Find(&fences).Error; err != nil {
		return false, errors.New("查询围栏失败: " + err.Error())
	}

	// 如果没有围栏数据，默认允许所有位置
	if len(fences) == 0 {
		log.Println("警告：没有找到有效的服务围栏，默认允许所有位置")
		return true, nil
	}

	// 检查位置是否在任何一个服务围栏内
	for _, fence := range fences {
		inFence, err := CheckPointInFence(lat, lng, fence)
		if err != nil {
			log.Printf("围栏检查失败 fenceId:%d, error:%v", fence.Id, err)
			continue // 单个围栏检查失败不影响其他围栏检查
		}
		if inFence {
			return true, nil
		}
	}

	return false, nil
}

// CheckPointInFence 检查点是否在围栏内（支持圆形围栏）
func CheckPointInFence(lat, lng float64, fence models.Fence) (bool, error) {
	// 根据围栏类型选择不同的检查算法
	switch fence.Type {
	case 1: // 圆形围栏
		return CheckPointInCircleFence(lat, lng, fence)
	default:
		return false, fmt.Errorf("不支持的围栏类型: %d", fence.Type)
	}
}
 
// CheckPointInCircleFence 检查点是否在圆形围栏内
func CheckPointInCircleFence(lat, lng float64, fence models.Fence) (bool, error) {
	// 计算两点之间的距离（使用Haversine公式）
	distance := untils.CalculateDistance(
		fence.Longitude, fence.Latitude,
		lng, lat,
	)

	// 假设围栏半径存储在Radius字段中，如果没有则使用默认值
	radius := fence.Radius
	if radius <= 0 {
		radius = 5000 // 默认5公里半径
	}

	// 如果距离小于等于围栏半径，则在围栏内
	return distance <= radius, nil
}

// 修改订单状态
func UpdateOrderStatus(in *__.UpdateOrderStatusReq) (models.Orders, error) {
	var o models.Orders
	var user models.User
	var p models.PricingInformation
	if err := p.PricingInformationOrderId(uint64(in.OrderId)); err != nil {
		return o, errors.New("查询订单失败" + err.Error())
	}
	o.Id = in.OrderId
	if err := o.GetOrderId(); err != nil {
		return o, errors.New("当前订单不存在" + err.Error())
	}
	var orderStatus string
	var orderStatusOld string
	orderStatusOld = orderStatus
	//计算状态变更耗时并更新直方图指标
	//计算从CreateAt时间（状态变更开始时记录的时间）到当前的耗时，转换为秒数。
	elapsed := time.Since(o.CreateAt).Seconds()
	//将耗时elapsed记录到直方图中，Prometheus 会自动按预设的 “分桶（Buckets）” 统计不同耗时区间的数量
	orderStatusChangeDuration.WithLabelValues(strconv.Itoa(int(o.OrderStatus)), strconv.Itoa(int(in.Status))).Observe(elapsed)
	//redis Stream 用作轻量事件总线

	// 司机可用性校验与选择：未指定司机则通过派单引擎决策
	var d models.Driver
	d.Id = uint32(in.DriverId)
	if err := d.GetDriverId(); err != nil {
		return o, errors.New("当前司机不存在" + err.Error())
	}
	d.CityId = uint32(in.CityId)
	if err := d.GetDriverCityId(); err != nil {
		return o, errors.New("查询司机城市失败" + err.Error())
	}

	if d.Status != 1 {
		return o, errors.New("当前司机状态不处于空闲状态")
	}

	// 保存原始订单状态，用于判断是否需要同步
	//originalStatus := int8(0)
	originalOrder := models.Orders{Id: o.Id}
	originalOrder.GetOrderInfo(int(o.Id))
	//originalStatus = originalOrder.OrderStatus

	o.OrderStatus = int8(in.Status)
	switch in.Status {
	case 3:
		user.Id = uint64(o.UserId)
		err := user.GetUserId()
		if err != nil {
			return o, fmt.Errorf("查询用户失败: %w", err)
		}
		//判断用户手机号后四位
		if user.Mobile[7:] != in.Mobile {
			return o, errors.New("用户手机号后四位不匹配")
		}
		o.DriverDepartTime = time.Now() //出发时间
	case 4:
		o.DriverArriveTime = time.Now() //到达时间
		o.ServiceEndTime = time.Now()   //服务结束时间
		// 计算订单实际距离
		distance, err := GetFinallyDistance(o.Id)
		if err != nil {
			return o, errors.New(err.Error())
		}
		o.Distance = distance
		// 获取实际价格（不再使用返回0的GetPrice()）
		actualPrice, err := GetOrderActualPrice(o.Id)
		if err != nil {
			log.Printf("获取订单实际价格失败: %v, 使用默认价格", err)
			actualPrice = 15.0 // 使用默认价格作为备用
		}
		o.Price = actualPrice
	}
	orderStatusCurrent.WithLabelValues(orderStatus, strconv.Itoa(int(o.CarTypeId))).Dec()
	if err := o.UpdateOrderStatus(); err != nil {
		return o, errors.New("修改订单状态失败" + err.Error())
	}

	// 当订单状态更新为已完成（状态5）时，实时同步交易信息到中央服务器
	if in.Status == 5 {
		go func() {
			// 使用goroutine异步调用，避免阻塞主流程
			if err := SyncTransactionToCentralServer(o.Id); err != nil {
				// 记录同步失败日志，实际应用中可以考虑重试机制
				log.Printf("同步订单ID=%d的交易信息失败: %v", o.Id, err)
			}
		}()
	}
	//更新当前状态指标
	orderStatusCurrent.WithLabelValues(orderStatus, strconv.Itoa(int(o.CarTypeId))).Inc()
	// 发布订单状态更新事件到 Redis Stream
	_ = config.Rdb.XAdd(config.Ctx, &redis.XAddArgs{
		Stream: "order_updateStatus" + strconv.Itoa(int(o.Id)),
		Values: map[string]interface{}{
			"orderId":        o.Id,
			"orderStatusOld": orderStatusOld,
			"orderStatusNew": orderStatus,
			"driverId":       in.DriverId,
			"changeTime":     time.Now().Format("2006-01-02 15:04:05"),
		},
	})
	return o, nil
}

// UpdateReassignStatus 修改改派状态
func UpdateReassignStatus(in *__.UpdateReassignStatusReq) (*models.Reassign, error) {
	var reassign models.Reassign
	var order models.Orders
	if err := reassign.GetReassignInfo(int(in.Id)); err != nil {
		return nil, errors.New("查找改派详情失败" + err.Error())
	}
	if reassign.Id == 0 {
		return nil, errors.New("改派申请不存在")
	}

	//开启事务
	tx := config.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	reassign.Status = uint8(in.Status)
	err := reassign.UpdateReassignStatus(int(in.Id))
	if err != nil {
		tx.Rollback()
		return nil, errors.New("更新改派状态失败" + err.Error())
	}

	if in.Status == 2 {
		order.Id = uint32(reassign.OrderId)
		order.DriverId = uint32(reassign.AssignDriver)
		if err := order.UpdateOrderDriverId(int(order.Id)); err != nil {
			tx.Rollback()
			return nil, errors.New("更新订单司机失败" + err.Error())
		}
	}
	//提交事务
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return nil, errors.New("提交事务失败" + err.Error())
	}
	return &reassign, nil
}

// 用户查看订单列表
func GetUserIdOrderInfo(in *__.GetUserIdOrderInfoReq) ([]*__.GetUserIdOrderInfo, error) {
	var order models.Orders
	order.UserId = in.UserId
	orderList, err := order.GetOrderList(in.UserId)
	if err != nil {
		return nil, errors.New("获取用户订单列表失败" + err.Error())
	}
	var (
		list []*__.GetUserIdOrderInfo
	)
	for _, o := range orderList {
		list = append(list, &__.GetUserIdOrderInfo{
			OrderSn:   o.OrderSn,
			OrderType: int32(o.OrderType),
			UserId:    o.UserId,
			DriverId:  o.DriverId,
			CityId:    o.CityId,
			Price:     float32(o.Price),
			CarTypeId: int32(o.CarTypeId),
			StartLoc:  o.StartLoc,
			EndLoc:    o.EndLoc,
		})
	}
	return list, nil
}

// 修改取消订单状态
func OrderCancellationUpdateStatus(in *__.OrderCancellationUpdateStatusReq) (models.OrderCancellation, error) {
	var OrderCancellation models.OrderCancellation
	var order models.Orders
	if err := OrderCancellation.GetCancelDetail(int(in.Id)); err != nil {
		return models.OrderCancellation{}, errors.New("查询失败" + err.Error())
	}
	if OrderCancellation.Id == 0 {
		return models.OrderCancellation{}, errors.New("取消订单不存在")
	}
	OrderCancellation.Id = in.Id
	OrderCancellation.Status = uint8(in.Status)
	fmt.Println("修改取消订单状态", in.Id, in.Status)
	if err := OrderCancellation.UpdateOrderCancellationStatus(int(in.Id)); err != nil {
		return models.OrderCancellation{}, errors.New("更新失败" + err.Error())
	}
	if in.Status == 2 {
		order.Id = uint32(OrderCancellation.OrderId)
		order.CancelTime = time.Now()
		order.OrderStatus = 6
		if err := order.UpdateOrderStatus(); err != nil {
			return models.OrderCancellation{}, errors.New("更新订单状态失败" + err.Error())
		}
	}
	return OrderCancellation, nil
}

// 手动发放用户优惠券
func UserCouponAdd(in *__.UserCouponAddReq) (*models.UserCoupon, error) {
	var uc models.UserCoupon
	var user models.User
	var coupon_template models.CouponTemplate
	user.Id = in.UserId
	err := user.GetUserId()
	if err != nil {
		return nil, errors.New("获取用户详情失败" + err.Error())
	}

	if user.Id == 0 {
		return nil, errors.New("用户不存在")
	}

	coupon_template.Id = in.CouponId
	err = coupon_template.GetCouponTemplate()
	if err != nil {
		return nil, errors.New("获取优惠券详情失败" + err.Error())
	}

	if coupon_template.Id == 0 {
		return nil, errors.New("优惠券不存在")
	}

	err = uc.GetUserCouponInfo(in.UserId, in.CouponId)
	if err != nil {
		return nil, errors.New("获取用户优惠券详情失败" + err.Error())
	}
	if uc.Id != 0 {
		return nil, errors.New("用户已发放该优惠券")
	}

	uc.UserId = in.UserId
	uc.CouponId = in.CouponId
	uc.Status = 2
	if err := uc.UserCouponAdd(); err != nil {
		return nil, errors.New("添加用户优惠券失败" + err.Error())
	}
	return &uc, nil
}

// 用户收藏优惠券
func UserCollectAdd(in *__.UserCollectAddReq) (*models.UserCoupon, error) {
	var uc models.UserCoupon
	var user models.User
	var coupon_template models.CouponTemplate
	user.Id = in.UserId
	err := user.GetUserId()
	if err != nil {
		return nil, errors.New("获取用户详情失败" + err.Error())
	}

	if user.Id == 0 {
		return nil, errors.New("用户不存在")
	}

	coupon_template.Id = in.CouponId
	err = coupon_template.GetCouponTemplate()
	if err != nil {
		return nil, errors.New("获取优惠券详情失败" + err.Error())
	}

	if coupon_template.Id == 0 {
		return nil, errors.New("优惠券不存在")
	}

	err = uc.GetUserCouponIn(in.CouponId)
	if err != nil {
		return nil, errors.New("获取用户优惠券详情失败" + err.Error())
	}
	if uc.Id != 0 {
		return nil, errors.New("用户已收藏该优惠券")
	}

	uc.UserId = in.UserId
	uc.CouponId = in.CouponId
	uc.Status = 1
	if err := uc.UserCouponAdd(); err != nil {
		return nil, errors.New("添加用户收藏优惠券失败" + err.Error())
	}
	return &uc, nil
}

// 用户分享优惠券
func UserShareCouponsAdd(in *__.UserShareCouponsAddReq) (*models.UserShareCoupons, error) {
	// 校验用户是否存在
	var user models.User
	user.Id = uint64(in.SharerId)
	err := user.GetUserId()
	if err != nil {
		return nil, errors.New("获取用户详情失败" + err.Error())
	}
	if user.Id == 0 {
		return nil, errors.New("用户不存在")
	}

	// 校验优惠券是否存在
	var coupon_template models.CouponTemplate
	coupon_template.Id = uint64(in.CouponId)
	err = coupon_template.GetCouponTemplate()
	if err != nil {
		return nil, errors.New("获取优惠券详情失败" + err.Error())
	}
	if coupon_template.Id == 0 {
		return nil, errors.New("优惠券不存在")
	}

	// 校验分享凭证是否存在
	var usc models.UserShareCoupons
	usc.ShareToke = in.ShareToke
	err = usc.GetUserShareCoupons()
	if err != nil {
		return nil, errors.New("获取用户分享优惠券详情失败" + err.Error())
	}
	if usc.Id != 0 {
		return nil, errors.New("分享凭证已存在")
	}
	return &usc, nil
}

// 优惠券列表
func CouponTemplateList(in *__.CouponTemplateListReq) ([]*__.CouponTemplateList, error) {
	// 校验优惠券模板是否存在
	var coupon_template models.CouponTemplate
	var list []*__.CouponTemplateList

	templateList, err := coupon_template.CouponTemplateList()
	if err != nil {
		return nil, errors.New("获取优惠券模板列表失败" + err.Error())
	}
	for _, template := range templateList {
		list = append(list, &__.CouponTemplateList{
			Title:        template.Title,
			CouponType:   uint64(template.CouponType),
			Description:  template.Description,
			Price:        float32(template.Price),
			Discount:     uint64(template.Discount),
			Limit:        uint64(template.Limit),
			SpecificCity: uint64(template.SpecificCity),
		})
	}
	return list, nil
}

// 优惠券模板搜索
func CouponTemplateSearch(in *__.CouponTemplateSearchReq) ([]*__.CouponTemplateSearch, error) {
	var coupon_template models.CouponTemplate
	var list []*__.CouponTemplateSearch
	templateList, err := coupon_template.CouponTemplateSearch(in.Title)
	if err != nil {
		return nil, errors.New("获取优惠券模板搜索列表失败" + err.Error())
	}
	for _, template := range templateList {
		list = append(list, &__.CouponTemplateSearch{
			Title:        template.Title,
			CouponType:   uint64(template.CouponType),
			Description:  template.Description,
			Price:        float32(template.Price),
			Discount:     uint64(template.Discount),
			Limit:        uint64(template.Limit),
			SpecificCity: uint64(template.SpecificCity),
		})
	}
	return list, nil
}

// 添加优惠券分享
func CouponSharesAdd(in *__.CouponSharesAddReq) (*models.CouponShares, error) {
	var couponShares models.CouponShares
	var coupon models.Coupon
	err := coupon.CouponDetail(in.CouponId)
	if err != nil {
		return nil, errors.New("优惠券查找失败存在")
	}
	if coupon.Id == 0 {
		return nil, errors.New("优惠券不存在")
	}
	couponShares.ShareBy = in.ShareBy
	couponShares.CouponId = in.CouponId
	couponShares.ShareTime = time.Now()
	if err := couponShares.CouponSharesAdd(); err != nil {
		return nil, errors.New("添加优惠券分享失败" + err.Error())
	}
	return &couponShares, nil
}

// 订单评论 - 乘客评价司机
func OrderComment(in *__.OrderCommentReq) (int64, error) {
	// 1. 验证订单是否存在且已完成
	var order models.Orders
	err := order.GetOrderInfo(int(in.OrderId))
	if err != nil {
		return 0, errors.New("订单不存在" + err.Error())
	}
	if order.OrderStatus != 5 {
		return 0, errors.New("订单未完成，无法评价")
	}
	if order.UserId != in.UserId {
		return 0, errors.New("用户与订单不匹配")
	}

	// 2. 验证是否已经评价过
	var existingComment models.OrderComment
	err = existingComment.GetOrderCommentByOrder(in.UserId, in.OrderId)
	if err == nil && existingComment.Id > 0 {
		return 0, errors.New("已经评价过该司机")
	}

	if time.Now().Unix()-order.UpdateAt.Unix() > 3600*24*2 {
		return 0, errors.New("超过48h后无法评论")
	}

	// 3. 创建评价
	var o models.OrderComment
	o.OrderId = in.OrderId
	o.UserId = in.UserId
	o.DriverId = order.DriverId // 从订单中获取司机ID
	o.Start = uint8(in.Start)
	o.Comment = in.Comment
	o.Tags = in.Tags
	o.Images = in.Images

	if err = o.CreateOrderComment(); err != nil {
		return 0, errors.New("评论失败" + err.Error())
	}
	return int64(o.Id), nil
}

// 计算订单实际距离
func GetFinallyDistance(orderId uint32) (float64, error) {
	var t models.Trajectory
	t.OrderId = orderId
	list, err := t.GetListByOrderId()
	if err != nil {
		return 0, errors.New("查询失败" + err.Error())
	}
	// 如果列表为空或只有一个点，总距离为0
	if len(list) < 2 {
		return 0, nil
	}
	var distanceSum float64
	for i := 0; i < len(list)-1; i++ {
		distance := untils.CalculateDistance(list[i].Longitude, list[i].Latitude, list[i+1].Longitude, list[i+1].Latitude)
		distanceSum += distance
	}
	return distanceSum, nil
}

type Resp struct {
	AvgPrice float64
	Date     string
}

func GetPrice() float64 {
	return 0
}

// 根据订单ID获取实际价格并保存明细
func GetOrderActualPrice(orderId uint32) (float64, error) {
	var order models.Orders
	if err := order.GetOrderInfo(int(orderId)); err != nil {
		return 0, err
	}

	// 计算各项费用明细
	var pricesStarting, mileageFee, durationFee float64

	// 起步价
	if order.CarTypeId == 1 {
		pricesStarting = 20
	} else if order.CarTypeId == 2 {
		pricesStarting = 30
	} else if order.CarTypeId == 3 {
		pricesStarting = 10
	} else {
		pricesStarting = 15
	}

	// 里程费（超出10公里部分）
	if order.Distance > 10 {
		mileageFee = (order.Distance - 10) * 3
	}

	// 时长费（如果有司机出发和到达时间）
	if !order.DriverDepartTime.IsZero() && !order.DriverArriveTime.IsZero() {
		durationMinutes := (order.DriverArriveTime.Unix() - order.DriverDepartTime.Unix()) / 60
		if durationMinutes > 0 {
			durationFee = float64(durationMinutes) * 0.5
		}
	}

	// 计算总价格
	totalPrice := pricesStarting + mileageFee + durationFee

	// 如果计算后价格仍为0，设置一个最小金额
	if totalPrice <= 0 {
		totalPrice = 10.0
	}

	// 创建或更新价格明细
	pricingInfo := &models.PricingInformation{}
	pricingInfo.OrderId = uint64(orderId)
	if err := pricingInfo.PricingInformationOrderId(uint64(orderId)); err != nil {
		// 如果不存在，创建新记录
		pricingInfo = &models.PricingInformation{
			OrderId:         uint64(orderId),
			PricesStarting:  pricesStarting,
			MileageFee:      mileageFee,
			DurationFee:     durationFee,
			LongDistance:    0,
			Bridge:          0,
			NightServiceFee: 0,
			ParkingFee:      0,
			Other:           0,
			TotalPrice:      totalPrice,
		}
		if err := pricingInfo.PricingInformationAdd(); err != nil {
			log.Printf("保存订单价格明细失败: %v，将继续使用计算价格", err)
		}
	} else {
		// 如果已存在，更新记录
		pricingInfo.PricesStarting = pricesStarting
		pricingInfo.MileageFee = mileageFee
		pricingInfo.DurationFee = durationFee
		pricingInfo.TotalPrice = totalPrice
		if err := pricingInfo.PricingInformationUpdate(); err != nil {
			log.Printf("更新订单价格明细失败: %v，将继续使用计算价格", err)
		}
	}

	return totalPrice, nil
}

// GetUserScheduledOrders 获取用户预约订单列表
func GetUserScheduledOrders(userId uint64) ([]*__.OrdersFilterOrderTypeList, error) {
	var order models.Orders
	order.UserId = uint32(userId)
	list, err := order.GetUserScheduledOrders()
	if err != nil {
		return nil, err
	}

	respList := make([]*__.OrdersFilterOrderTypeList, 0)
	for _, item := range list {
		respList = append(respList, &__.OrdersFilterOrderTypeList{
			Id:               item.Id,
			OrderSn:          item.OrderSn,
			OrderType:        int32(item.OrderType),
			UserId:           item.UserId,
			DriverId:         item.DriverId,
			CityLoc:          item.StartLoc,
			Price:            float32(item.Price),
			CarTypeId:        int32(item.CarTypeId),
			StartLoc:         item.StartLoc,
			EndLoc:           item.EndLoc,
			PayWay:           int32(item.PayWay),
			OrderStatus:      int32(item.OrderStatus),
			DriverDepartTime: item.DriverDepartTime.Format(time.DateTime),
			DriverArriveTime: item.DriverArriveTime.Format(time.DateTime),
			ServiceStartTime: item.ServiceStartTime.Format(time.DateTime),
			ServiceEndTime:   item.ServiceEndTime.Format(time.DateTime),
			PayTime:          item.PayTime.Format(time.DateTime),
			CancelTime:       item.CancelTime.Format(time.DateTime),
		})
	}

	return respList, nil
}

// CancelScheduledOrder 取消预约订单
func CancelScheduledOrder(orderId uint32, userId uint32) error {
	// 检查订单是否存在
	order := models.Orders{}
	err := config.DB.First(&order, orderId).Error
	if err != nil {
		return errors.New("订单不存在")
	}

	// 检查是否为当前用户的订单
	if order.UserId != userId {
		return errors.New("您无权取消该订单")
	}

	// 检查订单是否为预约单
	if order.OrderType != 2 {
		return errors.New("该订单不是预约订单")
	}

	// 检查订单状态是否允许取消
	if order.OrderStatus != 0 && order.OrderStatus != 1 {
		return errors.New("订单状态不允许取消")
	}

	// 取消订单
	err = config.DB.Model(&models.Orders{}).
		Where("id = ?", orderId).
		Update("order_status", 6).Error // 6 表示已取消
	if err != nil {
		return err
	}

	return nil
}

// PricingInformationAdd 添加收费信息
func PricingInformationAdd(in *__.PricingInformationAddReq) (*models.PricingInformation, error) {
	var p models.PricingInformation
	var sum float32
	var order models.Orders
	if err := order.GetOrderInfo(int(in.OrderId)); err != nil {
		return nil, errors.New("查找订单详情失败" + err.Error())
	}
	if order.Id == 0 {
		return nil, errors.New("订单不存在")
	}
	p.OrderId = in.OrderId
	if order.CarTypeId == 1 {
		p.PricesStarting = 20 // 起步价
	} else if order.CarTypeId == 2 {
		p.PricesStarting = 30 // 起步价
	} else if order.CarTypeId == 3 {
		p.PricesStarting = 10 // 起步价
	}

	if order.Distance > 10 {
		p.MileageFee = (order.Distance - 10) * 3 // 里程费
	}

	p.DurationFee = float64((order.DriverArriveTime.Unix()-order.DriverDepartTime.Unix())/60) * 0.5 // 时长费
	fmt.Println("时长费", order.DriverArriveTime.Unix(), order.DriverDepartTime.Unix())
	sum = float32(p.PricesStarting + p.MileageFee + p.DurationFee)

	p.LongDistance = float64(in.LongDistance)                                               // 远途费
	p.Bridge = float64(in.Bridge)                                                           // 过桥费
	p.NightServiceFee = float64(in.NightServiceFee)                                         // 夜间服务费
	p.ParkingFee = float64(in.ParkingFee)                                                   // 停车费
	p.Other = float64(in.Other)                                                             // 其他费用
	p.TotalPrice = float64(sum + in.Bridge + in.NightServiceFee + in.ParkingFee + in.Other) // 总价格
	if err := p.PricingInformationAdd(); err != nil {
		return nil, errors.New("添加订单价格信息失败" + err.Error())
	}
	order.Price = p.TotalPrice
	if err := order.UpdateOrderPrice(int(in.OrderId)); err != nil {
		return nil, errors.New("更新订单价格失败" + err.Error())
	}
	return &p, nil
}

func OrderDetail(in *__.OrderDetailReq) (*models.Orders, error) {
	var order models.Orders
	//order.Id = uint32(in.Id)
	order.UserId = uint32(in.UserId)
	err := order.GetOrderInfo(int(in.Id))
	if err != nil {
		return nil, errors.New("查找订单详情失败" + err.Error())
	}
	if order.Id == 0 {
		return nil, errors.New("订单不存在")
	}
	return &order, nil
}

func OrderTimeDetail(in *__.OrderTimeDetailReq) (*models.Orders, error) {
	var order models.Orders
	//order.Id = uint32(in.Id)
	order.UserId = uint32(in.UserId)
	err := order.GetOrderInfo(int(in.Id))
	if err != nil {
		return nil, errors.New("查找订单时间详情失败" + err.Error())
	}
	if order.Id == 0 {
		return nil, errors.New("订单不存在")
	}
	return &order, nil
}

// PricingInformationDetail 获取订单价格详情
func PricingInformationDetail(in *__.PricingInformationDetailReq) (*models.PricingInformation, error) {
	var p models.PricingInformation
	if err := p.PricingInformationOrderId(in.Id); err != nil {
		return nil, errors.New("查找订单价格详情失败" + err.Error())
	}
	if p.Id == 0 {
		return nil, errors.New("订单价格不存在")
	}
	return &p, nil
}

// 司机接单
func OrderDriverId(in *__.OrderDriverIdReq) (*models.Orders, error) {
	var order models.Orders
	if err := order.GetOrderInfo(int(in.OrderId)); err != nil {
		return nil, errors.New("查找订单详情失败" + err.Error())
	}
	if order.Id == 0 {
		return nil, errors.New("订单不存在")
	}

	var driver models.Driver
	if err := driver.GetDriverInfo(int(in.DriverId)); err != nil {
		return nil, errors.New("查找司机详情失败" + err.Error())
	}
	if driver.Id == 0 {
		return nil, errors.New("司机不存在")
	}

	if driver.IsInBlacklist == 1 {
		return nil, errors.New("司机已被拉入黑名单")
	}

	if driver.Status == 2 {
		return nil, errors.New("司机已被停用")
	}

	if driver.OrderStatus != 1 {
		return nil, errors.New("司机当前状态不允许接单")
	}
	// === 司机接单时检查司机位置围栏 ===
	driverLocation, err := GetDriverCurrentLocation(int64(in.DriverId))
	if err != nil {
		log.Printf("获取司机位置失败: %v", err)
		// 根据业务需求决定是否允许接单
		// return nil, errors.New("无法获取司机位置信息")
	} else {
		inFence, fenceErr := CheckLocationInServiceFence(driverLocation.Lat, driverLocation.Lng)
		if fenceErr != nil {
			log.Printf("围栏检查失败: %v", fenceErr)
			// 根据业务需求决定是否允许接单
		} else if !inFence {
			return nil, errors.New("司机不在服务区域内，无法接单")
		}
	}
	// === 围栏检查结束 ===
	order.DriverId = uint32(in.DriverId)
	if err := order.UpdateOrderDriverId(int(in.OrderId)); err != nil {
		return nil, errors.New("更新订单司机失败" + err.Error())
	}
	order.Id = uint32(in.OrderId)
	order.OrderStatus = 2 //司机已接单 待上车
	if err := order.UpdateOrderStatus(); err != nil {
		return nil, errors.New("更新订单状态失败" + err.Error())
	}
	order.ServiceStartTime = time.Now()
	if err := order.UpdateOrderServiceStartTime(); err != nil {
		return nil, errors.New("更新订单服务开始时间失败" + err.Error())
	}
	return &order, nil
}

// 获取司机当前位置
func GetDriverCurrentLocation(driverId int64) (struct {
	Lat float64
	Lng float64
}, error) {
	// 实现获取司机位置的逻辑
	// 可以从Redis、数据库或其他位置服务获取

	// 临时返回默认位置
	return struct {
		Lat float64
		Lng float64
	}{
		Lat: 39.9042,  // 默认纬度
		Lng: 116.4074, // 默认经度
	}, nil
}
